using System;
using System.Windows.Forms;
using CodePlex.TfsLibrary.ClientEngine;
using CodePlex.TfsLibrary.ObjectModel;

namespace CodePlex.CodePlexClientLibrary
{
    public class StatusGuiView : IStatusView
    {
        bool addedItems;
        readonly bool connectToServer;
        readonly string diffArgs;
        readonly string diffTool;
        readonly ITfsEngine engine;
        IStatusForm form;
        readonly string localPath;
        readonly string mergeArgs;
        readonly string mergeTool;
        StatusViewPresenter presenter;
        readonly bool recursive;
        readonly bool verbose;

        public StatusGuiView(ITfsEngine engine,
                             string localPath,
                             bool verbose,
                             bool recursive,
                             bool connectToServer,
                             string diffTool,
                             string diffArgs,
                             string mergeTool,
                             string mergeArgs)
        {
            this.engine = engine;
            this.verbose = verbose;
            this.diffTool = diffTool;
            this.diffArgs = diffArgs;
            this.mergeTool = mergeTool;
            this.mergeArgs = mergeArgs;
            this.localPath = localPath;
            this.recursive = recursive;
            this.connectToServer = connectToServer;
        }

        protected virtual IStatusForm CreateForm()
        {
            return new StatusForm();
        }

        protected virtual StatusViewPresenter CreatePresenter()
        {
            return new StatusViewPresenter(this, engine, verbose, recursive, connectToServer, diffTool, diffArgs, mergeTool, mergeArgs);
        }

        public void DisplayError(string path,
                                 SourceItemResult result)
        {
            ConsoleUtil.PrintCommandError(path, result);
        }

        public void DisplayItem(SourceItem item)
        {
            addedItems = true;
            form.DisplayItem(item);
        }

        public virtual void DisplayNoItemsMessage()
        {
            Console.WriteLine("No items to show.");
        }

        static bool IsItemAddedOrModified(SourceItem item)
        {
            return IsItemModified(item) || item.LocalItemStatus == SourceItemStatus.Add;
        }

        static bool IsItemModified(SourceItem item)
        {
            return (item.LocalItemStatus == SourceItemStatus.Modified ||
                    item.LocalItemStatus == SourceItemStatus.Conflict ||
                    item.LocalItemStatus == SourceItemStatus.Unversioned);
        }

        void OnItemAdd(object sender,
                       EventArgs<SourceItem> e)
        {
            presenter.DoAdd(e.Data);
        }

        void OnItemDelete(object sender,
                          EventArgs<SourceItem> e)
        {
            bool doDelete = true;

            if (IsItemAddedOrModified(e.Data))
                doDelete = MessageBox.Show("Are you sure you want to delete? You will lose your changes!", "Delete",
                                           MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
                                           MessageBoxDefaultButton.Button2) == DialogResult.Yes;

            if (doDelete)
                presenter.DoDelete(e.Data);
        }

        void OnItemDiff(object sender,
                        EventArgs<SourceItem> e)
        {
            presenter.DoDiff(e.Data);
        }

        void OnItemDiffMineAgainstBase(object sender,
                                       EventArgs<SourceItem> e)
        {
            presenter.DoDiffMineAgainstBase(e.Data);
        }

        void OnItemDiffTheirsAgainstBase(object sender,
                                         EventArgs<SourceItem> e)
        {
            presenter.DoDiffTheirsAgainstBase(e.Data);
        }

        void OnItemMerge(object sender,
                         EventArgs<SourceItem> e)
        {
            presenter.DoMerge(e.Data);
        }

        void OnItemResolve(object sender,
                           EventArgs<SourceItem> e)
        {
            presenter.DoResolve(e.Data);
        }

        void OnItemRevert(object sender,
                          EventArgs<SourceItem> e)
        {
            bool doRevert = true;

            if (IsItemModified(e.Data))
                doRevert = MessageBox.Show("Are you sure you want to revert? This operation cannot be undone!", "Revert",
                                           MessageBoxButtons.YesNo, MessageBoxIcon.Warning,
                                           MessageBoxDefaultButton.Button2) == DialogResult.Yes;

            if (doRevert)
                presenter.DoRevert(e.Data);
        }

        public bool QueryForResolve(string filename)
        {
            return (MessageBox.Show("Mark " + filename + " as resolved?", "Merge", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes);
        }

        public void RemoveItem(string path)
        {
            form.RemoveItem(path);
        }

        public virtual void Run()
        {
            form = CreateForm();
            form.ItemAdd += OnItemAdd;
            form.ItemDelete += OnItemDelete;
            form.ItemDiff += OnItemDiff;
            form.ItemDiffMineAgainstBase += OnItemDiffMineAgainstBase;
            form.ItemDiffTheirsAgainstBase += OnItemDiffTheirsAgainstBase;
            form.ItemMerge += OnItemMerge;
            form.ItemRevert += OnItemRevert;
            form.ItemResolve += OnItemResolve;
            form.LocalPath = localPath;

            presenter = CreatePresenter();
            presenter.Run(localPath);
        }

        public virtual bool ShowView()
        {
            if (!addedItems)
                return false;

            return form.ShowDialog() == DialogResult.OK;
        }
    }
}